/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package alloytoy;

import edu.mit.csail.sdg.alloy4.ConstList;
import edu.mit.csail.sdg.alloy4.Err;
import edu.mit.csail.sdg.alloy4.Version;
import edu.mit.csail.sdg.alloy4compiler.ast.Module;
import edu.mit.csail.sdg.alloy4compiler.ast.Sig;
import edu.mit.csail.sdg.alloy4compiler.translator.A4SolutionWriter;
import java.io.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import alloy2code.*;
import edu.mit.csail.sdg.alloy4.A4Reporter;
import edu.mit.csail.sdg.alloy4graph.GraphViewer;
import edu.mit.csail.sdg.alloy4viz.AlloyModel;
import edu.mit.csail.sdg.alloy4viz.AlloyType;
import edu.mit.csail.sdg.alloy4viz.VizGUI;
import edu.mit.csail.sdg.alloy4viz.VizState;
import edu.mit.csail.sdg.alloy4whole.SimpleGUI;
import tracetoautomata.*;
import boilerplates.*;

/**
 *
 * @author Daniel
 */

public class Main {
    static ArrayList<String> fileNames;
    static ArrayList<String> dirNames;
    static ArrayList<AlloyFunctions> models;
    public static Map<String,Integer> differences;
    public static String reportLocation;

    private static boolean dumpDiffModels;
    private static boolean calcFinalModels;
    private static boolean typeCheckModels;
    private static boolean printMetamodelsPng;
    private static boolean evolutionReport;
    private static boolean calcSignaturesImpact;

    public static void EvolutionReport(String fileName) throws IOException{
        BufferedWriter bwrite = new BufferedWriter(new FileWriter(fileName));
        bwrite.write(DotParser.sortByValue(differences).toString());
        bwrite.close();
    }

    public static void ComputeFinalModels(ArrayList<String> fileNames, ArrayList<String> dirNames){
        boolean crash=false;
        if(fileNames.size()==1) return;
        //System.out.println(dirNames.get(0)+"/"+fileNames.get(0));
        //System.out.println(dirNames.get(1)+"/"+fileNames.get(1));
        AlloyDif difA = new AlloyDif(dirNames.get(0)+"/"+fileNames.get(0),dirNames.get(1)+"/"+fileNames.get(1),dirNames.get(1)+"/Model.als");
        difA.ComputeDiff(models.get(1));
        
        if(fileNames.size()>2){
            for(int i=1; i<fileNames.size()-1; i++){
                /*System.out.println("Names:");
                System.out.println(dirNames.get(i));
                System.out.println(dirNames.get(i+1));*/
                AlloyDif difB = new AlloyDif(dirNames.get(i)+"/Model.als",dirNames.get(i+1)+"/"+fileNames.get(i+1),dirNames.get(i+1)+"/Model.als");
                difB.ComputeDiff(models.get(i+1));
            }
        }

    }

    public static ArrayList<AlloyFunctions> CreateModels(int num){
        ArrayList<AlloyFunctions> tmp = new ArrayList<AlloyFunctions>();
        for(int i=0; i<num; i++){
            tmp.add(new AlloyFunctions());
        }
        return tmp;
    }

    public static void InitModels(ArrayList<String> fileNames, ArrayList<String> dirNames) throws IOException{
        models.get(0).initAll(dirNames.get(0)+"/Dif1");
        for(int i=1; i<fileNames.size(); i++){
            models.get(i).initAll(dirNames.get(i)+"/Model.als");
        }
    }

    public static void A4Metamodel(String a4Filename, Module a4Module, String mmFilename) throws Err
    {
        try{
                Iterable<Sig> sigs = a4Module.getAllReachableSigs();
                PrintWriter of = new PrintWriter(mmFilename, "UTF-8");
                edu.mit.csail.sdg.alloy4.Util.encodeXMLs(of,"\n<alloy builddate=\"", Version.buildDate(), "\">\n\n");
                A4SolutionWriter.writeMetamodel(ConstList.make(sigs), a4Filename,of);
                edu.mit.csail.sdg.alloy4.Util.encodeXMLs(of, "\n</alloy>");
                edu.mit.csail.sdg.alloy4.Util.close(of);
            } catch (UnsupportedEncodingException e) {
                throw new edu.mit.csail.sdg.alloy4.ErrorAPI(e.getMessage(), e);
            } catch (FileNotFoundException e) {
                throw new edu.mit.csail.sdg.alloy4.ErrorAPI(e.getMessage(), e);
            }
     }
    public static void WriteMetaModels() throws Err{
        for(int i=0; i<dirNames.size(); i++){
            A4Metamodel(dirNames.get(i)+"model.als",models.get(i).fileChecked,dirNames.get(i)+"/metamodel.xml");
        }
    }

    public static void PrintPNGMetaModels() throws IOException{
        VizGUI viz = new VizGUI(true, dirNames.get(0)+"/metamodel.xml", null);
        viz.getViewer().alloySaveAsPNG(dirNames.get(0) + "/metamodel.png", 1, 1, 1);
        for(int i=1; i<dirNames.size(); i++){
            viz = new VizGUI(true,dirNames.get(i)+"/metamodel.xml", null);
            VizState stateviz = viz.getVizState();
            AlloyModel modelViz = stateviz.getCurrentModel();
            
            for (AlloyType t1 : modelViz.getTypes()) {
                System.out.println(t1.getName());
                if(models.get(i).diffSigs.contains(t1.getName()))
                {
                    //if(t1.getName().indexOf("Process")==-1)
                    stateviz.project(t1);
                }
            }
            viz.ApplyState();
            viz.getViewer().alloySaveAsPNG(dirNames.get(i) + "/metamodel.png", 1, 1, 1);
        }
        return;
    }

    public static void SignaturesImpact() throws IOException{
        for(int i=0; i<dirNames.size(); i++){
            XMLParser xmlParser = new XMLParser(dirNames.get(i)+"/metamodel.xml");
            Map<String,Integer> finalMap = xmlParser.parseFile();
            BufferedWriter bwrite = new BufferedWriter(new FileWriter(dirNames.get(i)+"/impact.txt"));
            bwrite.write(finalMap.toString());
            bwrite.close();
        }
    }

    //Write difmodels from texfile.
    public static void DumpDiffModels(){
        dumpDiffModels=true;
        TexParser tp = new TexParser(reportLocation);
        tp.ParseText();
        fileNames = tp.getNames();
        dirNames = tp.getDirNames();
        models = CreateModels(fileNames.size());
        
    }

    public static void CalcFinalModels(){
        calcFinalModels=true;
        if(!dumpDiffModels) DumpDiffModels();
        //Generatet final models to each section.
        ComputeFinalModels(fileNames,dirNames);
    }

    public static void TypeCheckModels() throws IOException{
        typeCheckModels=true;
        //Typecheck final models.
        if(!calcFinalModels) CalcFinalModels();
        InitModels(fileNames,dirNames);
    }

    public static void PrintMetamodelsPng() throws IOException, Err{
        printMetamodelsPng=true;
        if(!calcFinalModels) CalcFinalModels();
        if(!typeCheckModels) TypeCheckModels();
        //Write the metamodels in xml format.
        WriteMetaModels();
        //Prints all meta models to png format.
        PrintPNGMetaModels();
    }

    public static void EvolutionReport() throws IOException{
        if(!calcFinalModels) CalcFinalModels();
        EvolutionReport("Report.txt");
    }

    public static void CalcSignaturesImpact() throws IOException{
        if(!calcFinalModels) CalcFinalModels();
        SignaturesImpact();
    }

    private static void LaunchGui(String args[]) throws Exception {
        //if(!calcFinalModels) CalcFinalModels();
        //if(!typeCheckModels) TypeCheckModels();
        /*System.out.println(fileNames);
        System.out.println(dirNames);*/
        SimpleGUI.main(args);
    }
    public static void menu(String args[]) throws IOException, Err, Exception{
        Scanner in = new Scanner(System.in);
        int option;
        do{
            System.out.println("OPTIONS:");
            System.out.println("1 - Dump Diff Models.");
            System.out.println("2 - Calculate Final Models.");
            System.out.println("3 - Type Check Models.");
            System.out.println("4 - Print Metamodels.");
            System.out.println("5 - Calculate Evolution Report.");
            System.out.println("6 - Calculate Signatures Impact.");
            System.out.println("7 - Launch Alloy Gui");
            System.out.println("8 - Exit.");
            option = in.nextInt();
            switch(option){
                case 1: DumpDiffModels(); break;
                case 2: CalcFinalModels(); break;
                case 3: TypeCheckModels(); break;
                case 4: PrintMetamodelsPng(); break;
                case 5: EvolutionReport(); break;
                case 6: CalcSignaturesImpact(); break;
                case 7: LaunchGui(args); break;
                case 8: System.exit(1); break;
            }
        } while(true);
    }

    public static void main(String[] args) throws IOException, Err, Exception {
        differences = new HashMap<String,Integer>();
        reportLocation=args[0];
        dumpDiffModels=false;
        calcFinalModels=false;
        typeCheckModels=false;
        printMetamodelsPng=false;
        evolutionReport=false;
        calcSignaturesImpact=false;
        //menu(args);
        //AlloyFunctions mod = new AlloyFunctions();
        //mod.initAll(args[0]);
        
        //ArrayList<String> fileNames2 = Util.WriteXML("AlloyModel.als", A4Reporter.NOP,12,50,"tmpdir");
        //Util.BuildCompleteDFA("tmpdir/", fileNames2, "Photographer","graphs/");
        //Util u = new Util();
        //u.GraphvizUppaal("autoInitbefore.gv", "autoi.xml");
        //SimpleGUI tst = new SimpleGUI (args);
        //System.out.println(Util.dotToXMLMetamodel("GraphvizAutomaton.dot"));
        //System.out.println(args[0]);
        //Util.GetSubSigs("Ser", args[0]);
        //Util.OWLtoAlloy("ACC_System.owl", "OutputModel.als");
        Boilerplate bp = new Boilerplate("testefile.txt");
        HashMap<String,String> instance = new HashMap<String,String>();
        instance.put("System","ACC");
        instance.put("Action","FireMissiles");
        //System.out.println("String: "+bp.getInstanciatedModel(instance));
        Database db = new Database();
        //db.recreateDatabase();
        //db.insertBoilerplate(bp);
        ArrayList<Boilerplate> bps = db.getAllBoilerplates();
        Boilerplate tmp = db.getBoilerplate(12312);
        
            
            System.out.println("ID: "+tmp.getIdDB());
            System.out.println("IDBP: "+tmp.getId());
            System.out.println("DESC: "+tmp.getDescription());
            System.out.println("GENMODEL: "+tmp.getGenericModel());
        
       
    }

    
}